package com.bridgeintelligent.tag.webserver.security;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;

import com.bridgeintelligent.tag.utils.SecurityHelper;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.fasterxml.jackson.annotation.JsonInclude;

@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {
                org.apache.ibatis.mapping.MappedStatement.class,
                Object.class,
                org.apache.ibatis.session.RowBounds.class,
                org.apache.ibatis.session.ResultHandler.class,
                org.apache.ibatis.cache.CacheKey.class,
                org.apache.ibatis.mapping.BoundSql.class
        }),
        @Signature(type = Executor.class, method = "query", args = {
                org.apache.ibatis.mapping.MappedStatement.class,
                Object.class,
                org.apache.ibatis.session.RowBounds.class,
                org.apache.ibatis.session.ResultHandler.class
        }),
})
public class TagPermQueryPlugin implements Interceptor {

    static ObjectMapper jackson = new ObjectMapper();

    static {
        jackson.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        jackson.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement statement = (MappedStatement) args[0];
        if (args[1] == null) {
            args[1] = new MapperMethod.ParamMap<>();
        }
        MapperMethod.ParamMap<Object> parameters = (MapperMethod.ParamMap<Object>) args[1];
        BoundSql boundSql = statement.getBoundSql(parameters);
        String sql = boundSql.getSql();
        if (StringUtils.contains(sql, "dim_data")) {
            SessionTagPerms perms = fetchTagPerms();
            boundParams(parameters, perms);
        }
        return invocation.proceed();
    }

    private void boundParams(MapperMethod.ParamMap<Object> parameters, SessionTagPerms perms) {
        // 创建者=<用户ID> OR ( 归属部门 IN ( <部门ID> ) AND 标签权限='个人' ) OR ( 归属部门 IN ( <部门ID> )
        // AND 标签权限='部门' )
        // CREATER_ID, DEPARTMENT, BELONG_TO
        StringBuilder tagpermSQL = new StringBuilder();
        tagpermSQL.append(" CREATER_ID = '").append(perms.getUserId()).append("'");
        if (perms.getPersonalDepts() != null && perms.getPersonalDepts().size() > 0) {
            tagpermSQL.append(" OR ( BELONG_TO = '02' AND DEPARTMENT IN ( ");
            tagpermSQL.append(handleArrayParams(perms.getPersonalDepts()));
            tagpermSQL.append(" ) ");
        }
        if (perms.getPersonalDepts() != null && perms.getPersonalDepts().size() > 0) {
            tagpermSQL.append(" OR ( BELONG_TO = '03' AND DEPARTMENT IN ( ");
            tagpermSQL.append(handleArrayParams(perms.getPersonalDepts()));
            tagpermSQL.append(" ) ");
        }
        System.out.println("======> " + tagpermSQL);
        parameters.put("tagpermSQL", tagpermSQL.toString());
    }

    private String handleArrayParams(List<String> params) {
        StringBuilder r = new StringBuilder("");
        for (String param : params) {
            if (r.length() > 0) {
                r.append(",");
            }
            r.append("'").append(param).append("'");
        }
        return r.toString();
    }

    private SessionTagPerms fetchTagPerms() {
        Page<?> page;
        page = PageHelper.getLocalPage();
        if (page != null) {
            LocalPageHolder.holdLocalPage(null);
        }
        SessionTagPerms perms = SecurityHelper.tagperms();
        if (page != null) {
            LocalPageHolder.holdLocalPage(page);
        }
        page = PageHelper.getLocalPage();
        return perms;
    }

}
